package com.xuan.yubi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuan.yubi.common.ErrorCode;
import com.xuan.yubi.constant.AiFrequencyConstant;
import com.xuan.yubi.exception.BusinessException;
import com.xuan.yubi.manager.RedisLimiterManager;
import com.xuan.yubi.model.entity.AiFrequency;
import com.xuan.yubi.model.vo.AiFrequencyVo;
import com.xuan.yubi.service.AiFrequencyService;
import com.xuan.yubi.mapper.AiFrequencyMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;

/**
* @author ASUS
* @description 针对表【ai_frequency(AI分析调用表)】的数据库操作Service实现
* @createDate 2024-08-23 21:30:13
*/
@Service
public class AiFrequencyServiceImpl extends ServiceImpl<AiFrequencyMapper, AiFrequency>
    implements AiFrequencyService{

    @Resource
    private RedisLimiterManager redisLimiterManager;

    @Autowired
    private AiFrequencyMapper aiFrequencyMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public boolean getAiInvokeCount(Long userId) {
        // 1. 限制用户的调用次数，防止获取额外的次数
        String limitKey = AiFrequencyConstant.LIMIT_GET_COUNT + userId;
        redisLimiterManager.doRateLimitOnlyOne(limitKey);

        // 2. 从 redis 中查询最近调用该接口的时间
        // 若存在缓存则对比时间是否大于当天 0 点，是则直接返回 false
        String freeKey = AiFrequencyConstant.AI_FREQUENCY_FREE + userId;
        Date dateTime = (Date) redisTemplate.opsForValue().get(freeKey);
        if (dateTime != null && isAfterMidnight(dateTime)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "今日获取次数已达到上线");
        }

        // 3. 查询数据库中是否存在记录
        QueryWrapper<AiFrequency> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        AiFrequency aiFrequency = aiFrequencyMapper.selectOne(queryWrapper);
        if (aiFrequency == null) {
            // 创建新记录并返回
            AiFrequency aiFrequency1 = new AiFrequency();
            aiFrequency1.setUserId(userId);
            aiFrequency1.setRemainFrequency(AiFrequencyConstant.FREE_COUNT);
            return true;
        }
        if (aiFrequency.getUpdateTime() != null && isAfterMidnight(aiFrequency.getUpdateTime())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "今日获取次数已达到上线");
        }
        AiFrequency update = new AiFrequency();
        update.setId(aiFrequency.getId());
        update.setRemainFrequency(AiFrequencyConstant.FREE_COUNT);
        update.setUpdateTime(new Date());
        return aiFrequencyMapper.updateById(update) > 0;
    }

    @Override
    public AiFrequencyVo getAiFrequencyVo(Long userId) {
        QueryWrapper<AiFrequency> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId);
        AiFrequency aiFrequency = aiFrequencyMapper.selectOne(queryWrapper);
        // 1. 如果为空则创建记录
        if (aiFrequency == null) {
            aiFrequency = new AiFrequency();
            aiFrequency.setUserId(userId);
            aiFrequency.setRemainFrequency(0);
            aiFrequency.setTotalFrequency(0);
            aiFrequencyMapper.insert(aiFrequency);
        }
        // 2. 返回 VO 对象
        AiFrequencyVo aiFrequencyVo = new AiFrequencyVo();
        BeanUtils.copyProperties(aiFrequency, aiFrequencyVo);
        return aiFrequencyVo;
    }

    /**
     *  判断传入时间是否当前当天 0 点
     * @param date
     * @return
     */
    private boolean isAfterMidnight(Date date) {
        LocalDateTime midnight = LocalDateTime.of(
                LocalDateTime.now().getYear(),
                LocalDateTime.now().getMonth(),
                LocalDateTime.now().getDayOfMonth(),
                0, 0, 0, 0
        );

        Instant instant = date.toInstant();
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return localDateTime.isAfter(midnight);
    }
}




